#ifndef GAMEENGINE_GEOMETRY_TOPOLOGY_HALFEDGE_ACCESSOR_HPP
#define GAMEENGINE_GEOMETRY_TOPOLOGY_HALFEDGE_ACCESSOR_HPP

#ifdef GAMEENGINE_NAMESPACES
namespace GameEngine {
#endif

//=================================================================================
// Implementation of the HalfEdgeAccessor class

//! Constructor
/*!
 @param edge The half-edge to access
 */
template <class T>
HalfEdgeAccessor<T>::HalfEdgeAccessor(const HalfEdge<T>& edge) : edge_(edge) {}

//! Destructor
template <class T>
HalfEdgeAccessor<T>::~HalfEdgeAccessor() {}

//! Test if edge is belongs to the virtual exterior face
/*!
 @return True if edge belongs to the virtual exterior face, false otherwise
 */
template <class T>
bool HalfEdgeAccessor<T>::exterior_edge() const {
	return edge_.exterior_edge();
}

//! Accessor to the origin from which the half-edge is leaving
/*!
 @return An accessor to the origin from which the half-edge is leaving
 */
template <class T>
HalfEdgeVertexAccessor<T> HalfEdgeAccessor<T>::origin() const {
	return HalfEdgeVertexAccessor<T>(*edge_.origin());
}

//! Accessor to the face associated to the half-edge
/*!
 *  Caution: this function will result in an application crash when called on edges
 *  that belong to the virtual exterior face. The type of face to which the edge belongs
 *  should therefore ALWAYS be tested prior to calling that function; client code can
 *  do so by using the exterior_face() function, which returns true if edge belongs to
 *  the virtual exterior face.
 *
 *  An example of such a test would be:
 *  @code
 *  HalfEdgeAccessor<Type> accessor(edge);
 *
 *  // Edge does not belong to the virtual exterior face
 *  if ( accessor.exterior_face() == false ) {
 *		const HalfEdge<T>::Face& edge_face = accessor.face(); // no application crash
 *		// Do stuff...
 *  }
 *
 *  // Edge DOES belong to the virtual exterior face
 *  else {
 *		const HalfEdge<T>::Face& edge_face = accessor.face(); // /!\ Application crashes here!
 *		// Cannot do stuff - application will crash before going there...
 *  }
 *  @endcode
 *
 @return An accessor to the face associated to the half-edge
 */
template <class T>
HalfEdgeFaceAccessor<T> HalfEdgeAccessor<T>::face() const {
	return HalfEdgeFaceAccessor<T>(*edge_.face());
}

//! Accessor to the next half-edge of the face
/*!
 *  Caution: this function will result in an application crash when called on edges
 *  that belong to the virtual exterior face. The type of face to which the edge belongs
 *  should therefore ALWAYS be tested prior to calling that function; client code can
 *  do so by using the exterior_face() function, which returns true if edge belongs to
 *  the virtual exterior face.
 *
 *  An example of such a test would be:
 *  @code
 *  HalfEdgeAccessor<Type> accessor(edge);
 *
 *  // Edge does not belong to the virtual exterior face
 *  if ( accessor.exterior_face() == false ) {
 *		HalfEdgeAccessor<Type> next_accessor = accessor.next_edge(); // no application crash
 *		// Do stuff...
 *  }
 *
 *  // Edge DOES belong to the virtual exterior face
 *  else {
 *		HalfEdgeAccessor<Type> next_accessor = accessor.next_edge(); // /!\ Application crashes here!
 *		// Cannot do stuff - application will crash before going there...
 *  }
 *  @endcode
 *
 @return A half-edge accessor to the next half-edge of the face
 */
template <class T>
HalfEdgeAccessor<T> HalfEdgeAccessor<T>::next_edge() const {
	return HalfEdgeAccessor(*edge_.next_edge());
}

//! Accessor to the opposite half-edge
/*!
 @return A half-edge accessor to the opposite half-edge
 */
template <class T>
HalfEdgeAccessor<T> HalfEdgeAccessor<T>::opposite_edge() const {
	return HalfEdgeAccessor(*edge_.opposite_edge());
}

//=================================================================================
// Implementation of the HalfEdgeFaceAccessor class

//! Constructor
/*!
 @param face The half-edge face to access
 */
template <class T>
HalfEdgeFaceAccessor<T>::HalfEdgeFaceAccessor(const HalfEdgeFace<T>& face) : face_(face) {}

//! Destructor
template <class T>
HalfEdgeFaceAccessor<T>::~HalfEdgeFaceAccessor() {}

//! Accessor to the half-edge of the face
/*!
 @return A half-edge accessor to the half-edge of the face
 */
template <class T>
HalfEdgeAccessor<T> HalfEdgeFaceAccessor<T>::edge() const {
	return HalfEdgeAccessor(*face_.edge());
}

//! Detect the type of the half-edge face
/*!
 *  This function solely tests the consistency of the half-edges that belong to this face. All
 *  face-adjacency informations are ignored, hence may be inconsistent even if this face is
 *  considered valid. To detect adjacency issues, please use the face_type() function.
 *
 *  This function is quite costly (especially for the detection of InvalidLoop faces) and should
 *  therefore be used sparingly, if possible for debugging purposes only.
 *
 @return The type of the half-edge. This can either be OpenPathFace for faces that are topologically
         opened, InvalidLoopFace for faces whose half-edges define an ill-defined closed loop, or
		 ValidFace for other faces.
 */
template <class T>
typename HalfEdgeFace<T>::FaceType HalfEdgeFaceAccessor<T>::face_type() const {
	return face_.face_type();
}

//! Detect the adjacency type of the half-edge face
/*!
 *  This function assumes that edges in this face do not define an invalid edge loop,
 *  or this function would result in an infinite loop. An example of a face producing
 *  such an infinite loop could be: (example is written in pseudo-code)
 *  @code
 *  this_edge->next = edge1
 *  edge1->next = edge2
 *  edge2->next = edge3
 *  edge3->next = edge1
 *  @endcode
 *  Hence, the face defines a loop between edge1, edge2 and edge3, but never loops back
 *  to this_edge. Detecting such issues would be too costly to be practical - client
 *  code is therefore responsible for the validity of the face prior to calling this
 *  function.
 *
 @return The type of adjacency of the half-edge. This can either be OpenAdjacency for faces whose
         half-edges are not connected to another opposite half-edge, InconsistentOrientationAdjacency
		 if at least one of the adjacent face is not oriented consistently with this face,
		 UndefinedAdjacency if all half-edges cannot be traversed due to an internal invalidity
		 (please use the face_type() function to detect what, in the face, is inconsistent), or
		 ValidAdjacency for other faces.
 */
template <class T>
typename HalfEdgeFace<T>::AdjacencyType HalfEdgeFaceAccessor<T>::adjacency_type() const {
	return face_.adjacency_type();
}

//=================================================================================
// Implementation of the HalfEdgeVertexAccessor class

//! Constructor
/*!
 @param vertex The half-edge vertex to access
 */
template <class T>
HalfEdgeVertexAccessor<T>::HalfEdgeVertexAccessor(const HalfEdgeVertex<T>& vertex) : vertex_(vertex) {}

//! Destructor
template <class T>
HalfEdgeVertexAccessor<T>::~HalfEdgeVertexAccessor() {}

//! Accessor to the leaving half-edge of the vertex
/*!
 @return A half-edge accessor to the leaving half-edge of the vertex
 */
template <class T>
HalfEdgeAccessor<T> HalfEdgeVertexAccessor<T>::leaving_edge() const {
	return HalfEdgeAccessor(*vertex_.leaving_edge());
}

//! Accessor to the location associated to this vertex
/*!
 @return A constant reference to the location associated to this vertex
 */
template <class T>
const T& HalfEdgeVertexAccessor<T>::location() const {
	return vertex_.location();
}

#ifdef GAMEENGINE_NAMESPACES
} // namespace GameEngine
#endif

#endif
